<?php

// ------------------------------------------------------------------------
// |@Author       : Jarmin <topextend@qq.com>
// |@----------------------------------------------------------------------
// |@Date         : 2025-05-07 17:13:43
// |@----------------------------------------------------------------------
// |@LastEditTime : 2025-05-11 21:07:21
// |@----------------------------------------------------------------------
// |@LastEditors  : Jarmin <topextend@qq.com>
// |@----------------------------------------------------------------------
// |@Description  :
// |@----------------------------------------------------------------------
// |@FilePath     : LoadJwtAuth.php
// |@----------------------------------------------------------------------
// |@Copyright (c) 2025 http://www.ladmin.cn All Rights Reserved.
// ------------------------------------------------------------------------
declare (strict_types=1);

namespace think\admin\middleware;

use Closure;
use think\Request;
use think\Response;
use think\Exception;
// use think\admin\service\JwtService;
use think\admin\traits\ResponseTrait;
use think\exception\HttpResponseException;

/**
 * JWT认证中间件
 *
 * 主要功能：
 * 1. 验证JWT令牌有效性（支持HS256/HS384/HS512算法）
 * 2. 处理白名单路由跳过验证（支持通配符匹配）
 * 3. 统一异常处理和标准化错误响应
 * 4. 注入用户信息到请求对象（$request->user）
 *
 * @package think\admin\middleware
 * @version 1.2.0
 */
class LoadJwtAuth
{
    // use ResponseTrait;

    // /**
    //  * JWT服务实例
    //  * @var JWT
    //  */
    // protected $JwtService;

    /**
     * @var array 默认配置（会被用户配置覆盖）
     * 配置结构：
     * - jwt: JWT认证配置
     *   - secret   : 签名密钥（生产环境必须修改）
     *   - algo     : 签名算法（HS256/HS384/HS512）
     *   - excludes : 白名单路由（支持通配符）
     */
    // protected $config = [
    //     // JWT签名密钥（生产环境务必修改）
    //     'secret'   => '!@#L0.)A^7%D;*$Mk]"I?/(N',
    //     // 签名算法：HS256/HS384/HS512
    //     'algo'     => 'HS256',
    //     // 白名单路由（支持*通配符）
    //     'excludes' => [],
    // ];

    /**
     * 构造函数（依赖注入）
     * 配置加载流程：
     * 1. 初始化默认配置（包含基础JWT参数）
     * 2. 合并用户自定义配置（config/jwt.php）
     * 3. 最终配置存储到$config属性
     *
     * 安全提示：
     * - 生产环境必须修改默认secret密钥
     * - excludes配置建议通过配置文件管理
     *
     * @param JWT $serviceJWT 自动注入的JWT服务实例
     *                        包含令牌签发/验证核心逻辑
     */
    // public function __construct(JwtService $JwtService)
    // {
    //     // 合并配置（用户配置覆盖默认配置）
    //     $userConfig = config('jwt', []);
    //     $this->config = array_merge($this->config, $userConfig);

    //     // 注入JWT服务实例（依赖容器自动解析）
    //     $this->JwtService = $JwtService;
    // }

    /**
     * 中间件处理入口
     * 执行流程：
     * 1. 检查白名单路由（跳过验证）
     * 2. 执行JWT认证流程
     * 3. 统一异常捕获和处理
     *
     * @param Request $request 请求对象
     * @param Closure $next 中间件管道闭包
     * @return Response
     */
    public function handle(Request $request, Closure $next)
    {
        // try {
        //     // 检查白名单路由
        //     if ($this->shouldPassThrough($request)) {
        //         return $next($request);
        //     }

        //     // 执行JWT验证流程
        //     $this->authenticate($request);

        return $next($request);
        // } catch (HttpResponseException $e) {
        //     return $e->getResponse();
        // } catch (\Throwable $e) {
        //     return $this->handleException($e);
        // }
    }

    // /**
    //  * JWT认证流程
    //  * 安全验证要点：
    //  * 1. 令牌格式验证（Bearer Token规范）
    //  * 2. 签名算法验证（仅允许HS256/384/512）
    //  * 3. 密钥有效性验证（防止空密钥配置）
    //  * 4. 令牌时效性验证（exp claim自动校验）
    //  *
    //  * @throws HttpResponseException 以下情况会抛出异常：
    //  * - 令牌格式错误（错误码40101）
    //  * - 签名验证失败（错误码40100）
    //  * - 令牌已过期（错误码40102）
    //  * - 密钥配置错误（错误码50001）
    //  */
    // protected function authenticate(Request $request): void
    // {
    //     // 获取并验证令牌
    //     $token = $this->extractBearerToken($request);
    //     $secret = $this->getJwtSecret();

    //     try {
    //         // 解码令牌并注入用户信息
    //         $decoded = $this->JwtService->decode($token, $secret, ['HS256', 'HS384', 'HS512']);
    //         $request->user = (array)$decoded['user'];
    //     } catch (\Exception $e) {
    //         throw new HttpResponseException($this->getErrorMessage($e), $this->getErrorCode($e));
    //     }
    // }

    // /**
    //  * 统一异常处理
    //  * @param \Throwable $e 捕获的异常
    //  * @return Response 错误响应
    //  */
    // protected function handleException(\Throwable $e): Response
    // {
    //     if ($e instanceof HttpResponseException) {
    //         return $e->getResponse();
    //     }

    //     // 根据异常类型使用对应的响应方法
    //     return match(true) {
    //         strpos($e->getMessage(), 'expired') !== false => $this->unauthorized('令牌已过期'),
    //         strpos($e->getMessage(), 'invalid') !== false => $this->unauthorized('无效的令牌'),
    //         strpos($e->getMessage(), 'blacklist') !== false => $this->unauthorized('令牌已被禁用'),
    //         default => $this->unauthorized('未授权访问')
    //     };
    // }

    // /**
    //  * 检查白名单路由
    //  * @param Request $request 请求对象
    //  * @return bool 是否跳过验证
    //  */
    // protected function shouldPassThrough(Request $request): bool
    // {
    //     $path = '/' . trim($request->baseUrl(), '/');
    //     $excludes = $this->config['excludes'];
    //     foreach ($excludes as $pattern) {
    //         $pattern = '/' . trim($pattern, '/');
    //         // 转换通配符为正则表达式
    //         $regex = str_replace('\*', '.*', preg_quote($pattern, '#'));
    //         if (preg_match("#^{$regex}$#i", $path)) {
    //             return true;
    //         }
    //     }
    //     return false;
    // }

    // /**
    //  * 从请求头提取Bearer Token
    //  * @param Request $request 请求对象
    //  * @return string JWT令牌
    //  * @throws HttpResponseException 令牌不存在时抛出
    //  */
    // protected function extractBearerToken(Request $request): string
    // {
    //     $header = $request->header('Authorization', '');
    //     if (!preg_match('/Bearer\s+(\S+)/i', $header, $matches)) {
    //         throw new HttpResponseException($this->unauthorized('缺少访问令牌'));
    //     }
    //     return $matches[1];
    // }

    // /**
    //  * 获取JWT密钥
    //  * @return string JWT密钥
    //  * @throws HttpResponseException 配置错误时抛出
    //  */
    // protected function getJwtSecret(): string
    // {
    //     $secret = $this->config['secret'];
    //     if (empty($secret)) {
    //         throw new HttpResponseException($this->error('JWT密钥配置错误', self::SERVER_ERROR));
    //     }
    //     return $secret;
    // }
}
